/**
 * 
 */
package de.cbf.cam.dsa.facet.weapon_ranged;

import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import de.cbf.cam.dsa.facet.weapon_ranged.helper.WeaponRanged_CombatValues;
import de.cbf.util.entity.facet.constants.ConstantsFontColorLogView;
import de.cbf.util.entity.facet.entities.FacetOfEntity;
import de.cbf.util.entity.facet.util.TextPartStyled;
import de.cbf.util.uuidheader.entities.UUIDHeader;
import de.cbf.util.uuidheader.entities.UUIDReference;
import de.cbf.util.uuidheader.exceptions.EntityMergeException;

/**
 * @author Nebelritter
 * REMEMBER	best way: link with ammunitions on FK-Attack -> search only backpack, remember munitions
 */
@XmlRootElement(name="weapon_ranged")
@XmlAccessorType(XmlAccessType.FIELD)
public class FacetWeaponRanged extends FacetOfEntity implements FacetWeaponRangedConstants{	
	/** uuid of talent and the combat values 
	 */
	protected Map<UUIDReference, WeaponRanged_CombatValues> talentValuesMap;
	@XmlTransient
	protected Map<UUIDReference, PropertyChangeListener> talentPCLMap;
			
	public FacetWeaponRanged() {
		super();	
	}
	
	/* (non-Javadoc)
	 * @see de.cbf.util.uuidheader.entities.NamedEntity#init()
	 */
	@Override
	protected void init() {		
		super.init();
		talentValuesMap = new HashMap<UUIDReference, WeaponRanged_CombatValues>();
		talentPCLMap = new HashMap<UUIDReference, PropertyChangeListener>();
	}

	@Override
	protected void doMergeDataFrom(UUIDHeader entity, boolean i_am_older) throws EntityMergeException {
		super.doMergeDataFrom(entity, i_am_older);
		if (entity instanceof FacetWeaponRanged) {
			FacetWeaponRanged other = (FacetWeaponRanged) entity;
			if(i_am_older){				
				Set<UUIDReference> keys = other.talentValuesMap.keySet();
				//save all that are new and double in temp map
				Map<UUIDReference, WeaponRanged_CombatValues> tempTalentValuesMap = new HashMap<UUIDReference, WeaponRanged_CombatValues>();
				for (UUIDReference key : keys) {					
					WeaponRanged_CombatValues otherValue = other.talentValuesMap.get(key);
					WeaponRanged_CombatValues thisValue = this.talentValuesMap.get(key);
					if(thisValue == null){
						try {
							WeaponRanged_CombatValues clonedValue = (WeaponRanged_CombatValues) otherValue.clone();
							tempTalentValuesMap.put(key, clonedValue);
						} catch (CloneNotSupportedException e) {
							throw new EntityMergeException(e);
						}
					}else{
						thisValue.mergeDataFrom(otherValue);	
						tempTalentValuesMap.put(key, thisValue);
					}					
				}
				//remove all and add all from temp map
				this.talentValuesMap.clear();
				this.talentValuesMap.putAll(tempTalentValuesMap);				
			}
		}else{
			String mergeEntityClass = entity == null? "null":entity.getClass().getName();
			String errorMsg ="EntityToMerge "+mergeEntityClass+" does not fit class:"+this.getClass().getName();
			throw new EntityMergeException(errorMsg);
		}
	}
	@Override
	public List<TextPartStyled> getFacetStyledDescription() {
		List<TextPartStyled> textStyleInfo = new ArrayList<TextPartStyled>();
		
		TextPartStyled textPart;			
		//weaponRanged heading
		textPart = new TextPartStyled();
		textPart.setText(TEXT_LOG_HEADING_WEAPON_RANGED+"\n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_FACET);		
		textStyleInfo.add(textPart );
				
		Set<UUIDReference> keys = talentValuesMap.keySet();
		for (UUIDReference talentReference : keys) {
			//talent
			textPart = new TextPartStyled();
			textPart.setText(talentReference.getSavedName());
			textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
			textStyleInfo.add(textPart);
			
			textStyleInfo.addAll(getWeaponValueTextForTalent(talentReference));		
		}
		
		return textStyleInfo;
	}

	protected List<TextPartStyled> getWeaponValueTextForTalent(UUIDReference talentReference) {
		WeaponRanged_CombatValues weaponValues = talentValuesMap.get(talentReference);
		return weaponValues.getStyledDescription();
	}

	@Override
	public String hasUnsetValues() {
		StringBuffer result = new StringBuffer();
		if(talentValuesMap.isEmpty()){
			result.append(TEXT_UNSET_TALENT+"\n");
		}else{
			Set<UUIDReference> keys = talentValuesMap.keySet();			
			for (UUIDReference key : keys) {
				WeaponRanged_CombatValues combatValues = talentValuesMap.get(key);
				String unsetValues = combatValues.hasUnsetValues();
				if(unsetValues != null && ! unsetValues.isEmpty()){
					result.append(key.getSavedName()+"\n");
					result.append("\t"+unsetValues);
				}				
			}
		}	
		return result.toString();	
	}
	
	/* (non-Javadoc)
	 * @see de.cbf.util.entity.facet.entities.FacetOfEntity#setDeleted(java.lang.Long)
	 */
	@Override
	public void setDeleted(Long aDeleted) {		
		super.setDeleted(aDeleted);
		Collection<UUIDReference> keys = talentValuesMap.keySet();
		for (UUIDReference key : keys) {
			WeaponRanged_CombatValues value = talentValuesMap.get(key);
			if(value != null){
				value.setDeleted(aDeleted);
			}
			key.setDeleted(aDeleted);			
		}
	}
	
	public UUIDReference getTalentReferenceForUUID(UUID savedUUID) {
		Set<UUIDReference> keys = talentValuesMap.keySet();
		for (UUIDReference uuidReference : keys) {
			if(uuidReference.getSavedUuid().toString().equals(savedUUID.toString())){
				return uuidReference;
			}
		}
		return null;
	}
	
	public WeaponRanged_CombatValues getWeaponValuesByTalent(UUIDReference talent){
		return talentValuesMap.get(talent);
	}

	public void setWeaponValuesByTalent(UUIDReference talent,WeaponRanged_CombatValues values){
		talentValuesMap.put(talent, values);
		PropertyChangeListener pcl = new TalentValuesPCL(talent);
		values.getPropertyChangeSupport().addPropertyChangeListener(pcl);
		talentPCLMap.put(talent, pcl);
		propertyChangeSupport.fireIndexedPropertyChange(PN_TALENTS_VALUES, PI_TALENTS_VALUES, null, talentValuesMap);
	}

	public void removeWeaponValuesByTalent(UUIDReference talentReference){	
		if(talentReference == null) return;
		//get values to remove pcl from
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		//get pcl for talent
		PropertyChangeListener pcl = talentPCLMap.get(talentReference);
		//remove pcl
		values.getPropertyChangeSupport().removePropertyChangeListener(pcl);
		//remove mappings
		talentValuesMap.remove(talentReference);
		talentPCLMap.remove(talentReference);
		//fire PCE
		propertyChangeSupport.fireIndexedPropertyChange(PN_TALENTS_VALUES, PI_TALENTS_VALUES, null, talentValuesMap);
	}
	
	public List<UUIDReference> getTalents(){
		Set<UUIDReference> keys = talentValuesMap.keySet();
		List<UUIDReference> resultList = new ArrayList<UUIDReference>(keys);		
		return resultList;
	}
			
	public String getTp(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getTp();
	}
	
	public void setTp(UUIDReference talentReference, String newTp) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setTp(newTp);
	}
	
	public Integer getLoadingActions(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getLoadingActions();
	}

	public void setLoadingActions(UUIDReference talentReference,Integer valueInteger) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setLoadingActions(valueInteger);
	}
	
	public Double getRangeMin(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeMin();
	}
	public void setRangeMin(UUIDReference talentReference, double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeMin(doubleValue);
	}
	
	public Double getRangeVeryShort(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeVeryShort();
	}	
	public void setRangeVeryShort(UUIDReference talentReference,double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeVeryShort(doubleValue);
	}

	public Double getRangeShort(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeShort();
	}	
	public void setRangeShort(UUIDReference talentReference, double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeShort(doubleValue);
	}

	public Double getRangeMedium(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeMedium();
	}	
	public void setRangeMedium(UUIDReference talentReference, double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeMedium(doubleValue);
	}

	public Double getRangeLong(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeLong();
	}	
	public void setRangeLong(UUIDReference talentReference, double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeLong(doubleValue);
	}

	public Double getRangeExtremelyLong(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getRangeExtremelyLong();
	}	
	public void setRangeExtremelyLong(UUIDReference talentReference,double doubleValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setRangeExtremelyLong(doubleValue);
	}

	public Integer getDamageVeryShort(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getDamageVeryShort();
	}	
	public void setDamageVeryShort(UUIDReference talentReference,
			Integer valueInteger) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setDamageVeryShort(valueInteger);
	}

	public Integer getDamageShort(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getDamageShort();
	}	
	public void setDamageShort(UUIDReference talentReference,Integer valueInteger) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setDamageShort(valueInteger);
	}

	public Integer getDamageMedium(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getDamageMedium();
	}	
	public void setDamageMedium(UUIDReference talentReference,Integer valueInteger) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setDamageMedium(valueInteger);
	}

	public Integer getDamageLong(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getDamageLong();
	}	
	public void setDamageLong(UUIDReference talentReference,Integer valueInteger) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setDamageLong(valueInteger);
	}

	public Integer getDamageExtremelyLong(UUIDReference talentReference){
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		return values.getDamageExtremelyLong();
	}	
	public void setDamageExtremelyLong(UUIDReference talentReference,Integer intValue) {
		WeaponRanged_CombatValues values = talentValuesMap.get(talentReference);
		values.setDamageExtremelyLong(intValue);
	}	
	
	protected class TalentValuesPCL implements PropertyChangeListener{
		
		protected UUIDReference talent;

		public TalentValuesPCL(UUIDReference talent) {
			super();
			this.talent = talent;
		}

		/* (non-Javadoc)
		 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
		 */
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt instanceof IndexedPropertyChangeEvent) {
				IndexedPropertyChangeEvent idxEvt = (IndexedPropertyChangeEvent) evt;
				Object[] newValues = new Object[2];
				newValues[ARRAY_IDX_TALENT] = talent;
				newValues[ARRAY_IDX_VALUE] = evt.getNewValue();
				propertyChangeSupport.fireIndexedPropertyChange(idxEvt.getPropertyName(), idxEvt.getIndex(),
						idxEvt.getOldValue(), newValues);
			}else{
				Object[] newValues = new Object[2];
				newValues[ARRAY_IDX_TALENT] = talent;
				newValues[ARRAY_IDX_VALUE] = evt.getNewValue();
				propertyChangeSupport.firePropertyChange(evt.getPropertyName(),evt.getOldValue(),newValues);
			}
		}
	}

	

	
}

